﻿// -----------------------------------------------------------------------
// <copyright file="LocatorServiceBehavior.cs" company="Henadzi Sabaleuski.">
// Copyright (c) Henadzi Sabaleuski. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace OCM.Enterprise.OCR.Utilities.Unity
{
	#region Usings

	using System;
	using System.Collections.ObjectModel;
	using System.ServiceModel;
	using System.ServiceModel.Channels;
	using System.ServiceModel.Description;
	using System.ServiceModel.Dispatcher;

	using HSabaleuski.Utilities.Diagnostics;
	using Microsoft.Practices.ServiceLocation;

	#endregion

	/// <summary>
	/// The <see cref="IServiceBehavior"/> implementer which allows to modify or insert
	/// custom extensions across an entire service.
	/// </summary>
	public class LocatorServiceBehavior : IServiceBehavior
	{
		#region Private Fields

		/// <summary>
		/// The <see cref="IServiceLocator"/> field which used for Dependency Injection purposes.
		/// </summary>
		private readonly IServiceLocator serviceLocator;

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="LocatorServiceBehavior"/> class.
		/// </summary>
		/// <param name="serviceLocator">The service locator.</param>
		public LocatorServiceBehavior(IServiceLocator serviceLocator)
		{
			Guard.VerifyNullable(serviceLocator);

			this.serviceLocator = serviceLocator;
		}

		#endregion

		#region IServiceBehavior Members

		/// <summary>
		/// Provides the ability to pass custom data to binding elements to support the contract implementation.
		/// </summary>
		/// <param name="serviceDescription">The service description of the service.</param>
		/// <param name="serviceHostBase">The host of the service.</param>
		/// <param name="endpoints">The service endpoints.</param>
		/// <param name="bindingParameters">Custom objects to which binding elements have access.</param>
		public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
		{
			// Do Nothing. We do not use custom parameters for this behavior.
		}

		/// <summary>
		/// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
		/// </summary>
		/// <param name="serviceDescription">The service description.</param>
		/// <param name="serviceHostBase">The host that is currently being built.</param>
		public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
		{
			if (serviceDescription == null)
			{
				throw new ArgumentNullException("serviceDescription");
			}

			if (serviceHostBase == null)
			{
				throw new ArgumentNullException("serviceHostBase");
			}

			if (serviceHostBase.ChannelDispatchers != null)
			{
				// Set instance provider to each endpoint dispatcher for each channel dispatcher.
				foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
				{
					if (dispatcher != null && dispatcher.Endpoints != null)
					{
						foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
						{
							if (endpointDispatcher != null &&
								endpointDispatcher.DispatchRuntime != null &&
								serviceDescription.ServiceType != null)
							{
								endpointDispatcher.DispatchRuntime.InstanceProvider = new LocatorInstanceProvider(this.serviceLocator, serviceDescription.ServiceType);
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
		/// </summary>
		/// <param name="serviceDescription">The service description.</param>
		/// <param name="serviceHostBase">The service host that is currently being constructed.</param>
		public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
		{
			// Do Nothing. We do not implement validation logic for this behavior.
		}

		#endregion
	}
}